/***********************************************************************************************//**
*\n  @file       hardwares.cpp
*\n  @brief      硬件设备接口文件
*\n  @details
*\n -------------------------------------------------------------------------
*\n  文件说明：
*\n       1. 硬件设备接口文件
*\n       2. 定义硬件设备接口
*\n       3. C++设计，并提供C接口
*\n
*\n -------------------------------------------------------------------------
*\n  版本:   修改人:   修改日期:       描述:
*\n  V0.01   罗先能    2017.5.3       创建
*\n  V0.02   罗先能    2021.7.15     添加详细注释文档
*\n
***************************************************************************************************/

/**************************************************************************************************
* 头文件
***************************************************************************************************/
#include "vme.h"
#include <iostream>
// 接口
#include "bus.hpp"
#include "bus_spi.hpp"
#include "bus_gpio.hpp"
#include "bus_uart.hpp"
// 设备
#include "device.hpp"
#include "device_gpio.hpp"
#include "device_uart.hpp"
#include "hardwares.h"

#undef  DEBUG_LEVEL
#define DEBUG_LEVEL 2    // 定义debug级别 (0 ~ 5)
#include "vdebug.h"


using namespace std;


/**************************************************************************************************
* 宏定义、结构定义
***************************************************************************************************/
typedef struct DeviceTabItem
{
	DEV_NO     iNo;			 ///< 设备index
	TDevice    *pDev;		 ///< 设备指针
} DeviceTabItem;


/**************************************************************************************************
* 全局变量声明、定义
***************************************************************************************************/


/**************************************************************************************************
* 私有变量声明、定义
***************************************************************************************************/


/**************************************************************************************************
* 私有函数声明、定义
***************************************************************************************************/
#if 1
// ------------------------------------------------
// 1. 定义总线
// ------------------------------------------------
static TGpioBus         tGpioBus1("gpioBus1",     0xe000a000);        // General Purpose I/O
static TSpiBus          tSpi2Uart0("spi2Uart0",   SPI_UART0);
static TSpiBus          tSpi2Uart1("spi2Uart1",   SPI_UART1);
static TBus             tDnaBus1  ("DnaBus1",     0x43c00000);       // DNA Address

// ------------------------------------------------
// 2. 定义设备
// ------------------------------------------------
//static TGpioFs          tGpio38("mio38", MIO38, OUTPUT, 1 /* 0: low,1: high */);
static TGpioFs          tGpio39("mio39", MIO39, INPUT,  2 /* 1: rising,2: falling */);

static TRs232           tRs485a("rs485a",   PS_UART1);
static TRs232FromSpi    tRs485b("rs485b",   &tGpio39, &tSpi2Uart0, 0 /* 0: spi2Uart0 */);
static TRs232FromSpi    tRs232 ("rs232",    &tGpio39, &tSpi2Uart1, 1 /* 1: spi2Uart1 */);
static TDevice          tDnaDevice1("DNA1", &tDnaBus1);

// ------------------------------------------------
// 3. 设备表
// ------------------------------------------------
static const DeviceTabItem psDevices[DEV_NO_MAX + 1] =
	{
		{ DEV_NO_GPIO38,         NULL     },
		{ DEV_NO_GPIO39,         &tGpio39 },

		{ DEV_NO_RS485A,         &tRs485a },
		{ DEV_NO_RS485B,         &tRs485b },
		{ DEV_NO_RS232,          &tRs232  },

		{ DEV_NO_DNA,            &tDnaDevice1 },

		{ DEV_NO_MAX, NULL },  //not used
};
#endif




/**************************************************************************************************
* 全局函数声明、定义
***************************************************************************************************/

/*************************************************************************************//**
*\n 函数名称： HwOpen() / HwClose()
*\n 功能描述：
*\n            打开(关闭)硬件设备
*\n 输入参数：
*\n            DEV_NO id      : 设备编号
*\n            void* pHandle  : 设备句柄数据结构(每个设备不相同)
*\n 输出参数:
*\n
*\n 返 回 值:
*\n           0 成功; -1 失败; -n    错误码
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.7.15     创建
*****************************************************************************************/
extern "C" int HwOpen(DEV_NO id, void *pHandle)
{
	if (id >= DEV_NO_MAX)
	{
		debug_error("id==%d,out of range[0..DEV_NO_MAX] \r\n", id);
		return (-1);
	}

	TDevice *pDev = psDevices[id].pDev;
	if (NULL == pDev)
	{
		debug_error("psDevices[%d].pDev == null \r\n", id);
		return (-1);
	}

	int iRet;
	iRet = pDev->Open(pHandle);
	return (iRet);
}

// 关闭设备
extern "C" int HwClose(DEV_NO id, void *pHandle)
{
	if (id >= DEV_NO_MAX)
	{
		debug_error("id==%d,out of range[0..DEV_NO_MAX] \r\n", id);
		return (-1);
	}

	TDevice *pDev = psDevices[id].pDev;
	if (NULL == pDev)
	{
		debug_error("psDevices[%d].pDev == null \r\n", id);
		return (-1);
	}

	int iRet;
	iRet = pDev->Close(pHandle);
	return (iRet);
}

/*************************************************************************************//**
*\n 函数名称： HwLoad()
*\n 功能描述：
*\n            下载fpga的bit流文件到FPGA(专用)
*\n 输入参数：
*\n            DEV_NO id         : 设备编号
*\n            const char* pFile : 下载的FPGA文件（/path/fpga.bit）
*\n 输出参数:
*\n
*\n 返 回 值:
*\n           0 成功; -1 失败; -n    错误码
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.7.15     创建
*****************************************************************************************/
extern "C" int HwLoad(DEV_NO id, const char *pFile)
{
	if (id >= DEV_NO_MAX)
	{
		debug_error("id==%d,out of range[0..DEV_NO_MAX] \r\n", id);
		return (-1);
	}

	TDevice *pDev = psDevices[id].pDev;
	if (NULL == pDev)
	{
		debug_error("psDevices[%d].pDev == null \r\n", id);
		return (-1);
	}

	int iRet;
	iRet = pDev->Load(pFile);
	return (iRet);
}


/*************************************************************************************//**
*\n 函数名称： HwLock()  / HwUnlock()
*\n 功能描述：
*\n            设备的锁 、开锁
*\n 输入参数：
*\n            DEV_NO id        : 设备编号
*\n 输出参数:
*\n
*\n 返 回 值:
*\n           0 成功; -1 失败; -n    错误码
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.7.15     创建
*****************************************************************************************/
extern "C" int HwLock(DEV_NO id)
{
	if (id >= DEV_NO_MAX)
	{
		debug_error("id==%d,out of range[0..DEV_NO_MAX] \r\n", id);
		return (-1);
	}

	TDevice *pDev = psDevices[id].pDev;
	if (NULL == pDev)
	{
		debug_error("psDevices[%d].pDev == null \r\n", id);
		return (-1);
	}

	int iRet;
	iRet = pDev->Lock();
	return (iRet);
}

// 设备开锁
extern "C" int HwUnlock(DEV_NO id)
{

	if (id >= DEV_NO_MAX)
	{
		debug_error("id==%d,out of range[0..DEV_NO_MAX] \r\n", id);
		return (-1);
	}

	TDevice *pDev = psDevices[id].pDev;
	if (NULL == pDev)
	{
		debug_error("psDevices[%d].pDev == null \r\n", id);
		return (-1);
	}

	int iRet;
	iRet = pDev->Unlock();
	if (0 > iRet)
	{
		debug_error("psDevices[%d]->Unlock() < 0 \r\n", id);
		return (-1);
	}

	return (0);
}


/*************************************************************************************//**
*\n 函数名称： HwRead() / HwWrite()
*\n 功能描述：
*\n            从硬件设备读/写数据
*\n 输入参数：
*\n            DEV_NO id         : 设备编号
*\n            long offset       : 偏移地址
*\n            void *pBuf        : 数据buffer
*\n            long iSizeToRead  : 需要读出数据的长度（byte单位）
*\n            long iSizeToWrite : 需要写入数据长度（byte单位）
*\n 输出参数:
*\n
*\n 返 回 值:
*\n           实际读出/写入的数据个数（byte单位）;
*\n           -1 失败;
*\n           -n 错误码;
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.7.15     创建
*****************************************************************************************/
extern "C" int HwRead(DEV_NO id, long offset, void *pBuf, long iSizeToRead)
{

	if (id >= DEV_NO_MAX)
	{
		debug_error("id==%d,out of range[0..DEV_NO_MAX] \r\n", id);
		return (-1);
	}

	TDevice *pDev = psDevices[id].pDev;
	if (NULL == pDev)
	{
		debug_error("psDevices[id]->pDev == NULL\n", id);
		return (-1);
	}

	int iRet = pDev->Read(offset, pBuf, iSizeToRead);
	if (iRet < 0)
	{
		debug_error("psDevices[id]->Read() < 0\n", id);
		return (-1);
	}
	return (iRet);
}

/*************************************************************************************//**
*\n 函数名称： HwRead() / HwWrite()
*\n 功能描述：
*\n            从硬件设备读/写数据
*\n 输入参数：
*\n            DEV_NO id         : 设备编号
*\n            long offset       : 偏移地址
*\n            void *pBuf        : 数据buffer
*\n            long iSizeToRead  : 需要读出数据的长度（byte单位）
*\n            long iSizeToWrite : 需要写入数据长度（byte单位）
*\n 输出参数:
*\n
*\n 返 回 值:
*\n           实际读出/写入的数据个数（byte单位）;
*\n           -1 失败;
*\n           -n 错误码;
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.7.15     创建
*****************************************************************************************/
extern "C" int HwWrite(DEV_NO id, long offset, void *pBuf, long size)
{

	if (id >= DEV_NO_MAX)
	{
		debug_error("id==%d,out of range[0..DEV_NO_MAX] \r\n", id);
		return (-1);
	}

	TDevice *pDev = psDevices[id].pDev;
	if (NULL == pDev)
	{
		debug_error("psDevices[%d].pDev==NULL\n", id);
		return (-1);
	}

	int iRet;
	iRet = pDev->Write(offset, pBuf, size);
	if (0 > iRet)
	{
		debug_error("psDevices[id]->Write() < 0\n", id);
		return (-1);
	}
	return (iRet);
}


/*************************************************************************************//**
*\n 函数名称： HwIoctl()
*\n 功能描述：
*\n            控制设备的操作
*\n 输入参数：
*\n            DEV_NO id        : 设备编号
*\n            long cmd         : 控制命令
*\n            void *pBuf       : 控制数据（输入）
*\n            long *pSize      : 数据长度（输入）
*\n 输出参数:
*\n            void *pBuf       : 输出数据（输出）
*\n            long *pSize      : 数据长度（输出）
*\n
*\n 返 回 值:
*\n           0 成功; -1 失败; -n    错误码
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.7.15     创建
*****************************************************************************************/
extern "C" int HwIoctl(DEV_NO id, long cmd,  /*INOUT*/ void *pBuf, /*INOUT*/ long *pSize)
{

	if (id >= DEV_NO_MAX)
	{
		debug_error("id==%d,out of range[0..DEV_NO_MAX] \r\n", id);
		return (-1);
	}

	TDevice *pDev = psDevices[id].pDev;
	if (NULL == pDev)
	{
		debug_error("psDevices[%d].pDev==NULL\n", id);
		return (-1);
	}

	int iRet;
	iRet = pDev->Ioctl(cmd, pBuf, pSize);
	if (0 > iRet)
	{
		debug_error("psDevices[%d].Ioctl() < 0\n", id);
		return (-1);
	}

	return (0);
}

/*************************************************************************************//**
*\n 函数名称： DevicesInit()
*\n 功能描述：
*\n            初始化全部设备（调用设备的初始化函数）
*\n 输入参数：
*\n 输出参数:
*\n
*\n 返 回 值:
*\n           0 成功; -1 失败; -n    错误码
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.7.15     创建
*****************************************************************************************/
extern "C" int DevicesInit()
{
	TDevice *pDev;
	for (int id = 0; id < DEV_NO_MAX; id++)
	{
		pDev = psDevices[id].pDev;
		if (NULL != pDev)
		{
			pDev->Init();
		}
	}

	return (0);
}


// 初始化设备
// extern "C" int HwInit(DEV_NO id)
// {
// 	int iRet;
// 	TDevice *pDev = NULL;

// 	if ((id <= DEV_NO_MIN) || (id >= DEV_NO_MAX))
// 	{
// 		debug_error("id==%d,out of range[DEV_NO_MIN, DEV_NO_MAX] \r\n", id);
// 		return -1;
// 	}

// 	pDev = psDevices[id].pDev;
// 	if (NULL == pDev)
// 	{
// 		return -1;
// 	}

// 	iRet = pDev->Init();
// 	return (iRet);
// }

